class TaskQueue {
	constructor(maxNum) {
		this.maxNum = maxNum // 并发池数量大小
		this.running = 0 // 当前正在执行的池数
		this.queue = [] // 任务队列
		this.queueIndex = 0 // 当前进入执行的任务索引顺序
		this.results = {} // 存储任务执行结果
		this.callback = null // 回调函数
		this.isPushOver = false // 任务是否追加完毕
	}

	// 追加任务，并执行
	pushTasks(tasks) {
		this.queue.push(...tasks)
		this.next()
	}

	// 通知任务追加完毕
	pushOver() {
		this.isPushOver = true
		this.runOver()
	}

	// 任务全部执行完毕
	runOver() {
		if (
			typeof this.callback === 'function' &&
			this.running == 0 &&
			this.isPushOver
		) {
			this.callback.call(null, this.results)
		}
	}

	async next() {
		while (this.running < this.maxNum && this.queue.length) {
			const task = this.queue.shift()
			// 标识当前任务索引，方便从 results 取用值
			const key = task?.key || this.queueIndex
			this.queueIndex++
			// 任务池被占用数量+1
			this.running++
			// 任务临界判断合法性
			if (!task) {
				this.results[key] = null
				this.running--
				continue
			}
			// 执行任务
      try {
        this.results[key] = await task.fn()
      } catch (error) {
        this.results[key] = error
      }
      this.running--
      this.next()
		}
		this.runOver()
	}
}

/**
 * 测试用例
 */

function run() {
	// 创建实例
	const queue = new TaskQueue(5)
	queue.callback = (result) => {
		console.log('asyncPool_1 ~ result:', result)
		console.log(result[1]) // 支持按顺序取用结果
		console.log(result.four) // 支持针对特殊任务取用结果
	}

	function buildTask(result, delay = 0) {
		return () =>
			new Promise((resolve) =>
				setTimeout(() => {
					console.log('正在执行任务', result)
					resolve(result)
				}, delay)
			)
	}

	const tasks = [
		{ fn: buildTask(1, 1000) },
		{ fn: buildTask(2, 2000) },
		{ fn: buildTask(3, 3000) },
		{ fn: buildTask(4, 1000), key: 'four' }, // key
	]
	queue.pushTasks(tasks)
	setTimeout(() => {
		console.log('再追加一个任务')
		queue.pushTasks([{ fn: buildTask(5, 100), key: 5 }])
	}, 500)

	setTimeout(() => {
		console.log('通知追加结束')
		queue.pushOver()
	}, 700)
}

run()

class TaskQueue {
	constructor(maxConcurrent = 3) {
		this.maxConcurrent = maxConcurrent
		this.running = []
		this.queue = []
	}

	enqueue(task) {
		this.queue.push(task)
		this._processQueue()
	}

	async _processQueue() {
		while (this.running.length < this.maxConcurrent && this.queue.length) {
			const task = this.queue.shift()
			this.running.push(task)
      try {
        await task()
      } catch (error) {
        console.error('TaskQueue error:', error)
      }
      this._processQueue()
      this.running = this.running.filter((t) => t !== task)
		}
	}
}

// 使用示例
const taskQueue = new TaskQueue(2) // 最多同时执行2个请求

// 假设有一个异步请求函数
const fetchData = async (url) => {
	const response = await fetch(url)
	return await response.json()
}

// 将请求加入队列
taskQueue.enqueue(() => fetchData('https://api.example.com/data1'))
taskQueue.enqueue(() => fetchData('https://api.example.com/data2'))
taskQueue.enqueue(() => fetchData('https://api.example.com/data3'))
// ...以此类推，请求会被顺序加入队列，并且最多同时执行2个


const onec = (fn) => {
	var flag = true
	return function () {
		if (flag) {
			flag = false
			return fn.apply(this, arguments)
		}
	}
}